package org.eirudy.shareimage.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.eirudy.shareimage.exception.BusinessException;
import org.eirudy.shareimage.exception.ErrorCode;
import org.eirudy.shareimage.exception.ThrowUtils;
import org.eirudy.shareimage.mapper.SpaceMapper;
import org.eirudy.shareimage.model.dto.space.analyze.*;
import org.eirudy.shareimage.model.entity.Picture;
import org.eirudy.shareimage.model.entity.Space;
import org.eirudy.shareimage.model.entity.User;
import org.eirudy.shareimage.model.vo.SpaceUserAnalyzeResponse;
import org.eirudy.shareimage.model.vo.SpaceVO;
import org.eirudy.shareimage.model.vo.space.analyze.SpaceCategoryAnalyzeResponse;
import org.eirudy.shareimage.model.vo.space.analyze.SpaceSizeAnalyzeResponse;
import org.eirudy.shareimage.model.vo.space.analyze.SpaceTagAnalyzeResponse;
import org.eirudy.shareimage.model.vo.space.analyze.SpaceUsageAnalyzeResponse;
import org.eirudy.shareimage.service.SpaceAnalyzeService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author Eirudy
*/
@Service
public class SpaceAnalyzeServiceImpl extends ServiceImpl<SpaceMapper, Space>
implements SpaceAnalyzeService {


    @Resource
    private  UserServiceImpl userServiceImpl;

    @Resource
    private SpaceServiceImpl spaceServiceImpl;

    @Resource
    private PictureServiceImpl pictureServiceImpl;

    /**
     *  负责返回空间分析的结果
     * @param spaceUsageAnalyzeRequest
     * @param loginUser
     * @return
     */
    @Override
    public SpaceUsageAnalyzeResponse getSpaceUsageAnalyzeResponse(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceUsageAnalyzeRequest == null,ErrorCode.PARAMS_ERROR );
        Long spaceId = spaceUsageAnalyzeRequest.getSpaceId();
        boolean queryPublic = spaceUsageAnalyzeRequest.isQueryPublic();
        boolean queryAll = spaceUsageAnalyzeRequest.isQueryAll();
        // 校验参数
        // 全空间或公共图库，需要从Picture表查询
        if(queryPublic || queryAll) {
            //权限校验，仅管理员访问
            checkSpaceAnalyzeAuth(spaceUsageAnalyzeRequest, loginUser);
            // 统计使用的空间
            QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("picSize");
            fillAnalyzeQueryWrapper(spaceUsageAnalyzeRequest,queryWrapper);

            List<Object> objects = pictureServiceImpl.getBaseMapper().selectObjs(queryWrapper);

            long usedSize = objects.stream().mapToLong(obj -> (Long)obj).sum();
            long usedCount = objects.size();

            // 封装返回结果
            SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
            spaceUsageAnalyzeResponse.setUsedSize(usedSize);
            // 分析公共图库，无容量限制，无比例
            spaceUsageAnalyzeResponse.setMaxSize(null);
            spaceUsageAnalyzeResponse.setSizeUsageRatio(null);
            spaceUsageAnalyzeResponse.setUsedCount(null);
            spaceUsageAnalyzeResponse.setMaxCount(null);
            spaceUsageAnalyzeResponse.setCountUsageRatio(null);
            return spaceUsageAnalyzeResponse;
            
        }else {
            // 特定空间可以从Space查询
            ThrowUtils.throwIf(spaceId == null || spaceId <=0,ErrorCode.PARAMS_ERROR,"参数异常");
            Space space = spaceServiceImpl.getById(spaceId);

            // 判断空间是否存在
            ThrowUtils.throwIf(space == null , ErrorCode.NOT_FOUND_ERROR,"空间不存在");
            // 校验一下权限
            checkSpaceAnalyzeAuth(spaceUsageAnalyzeRequest, loginUser);

            // 设置一下参数
            SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
            spaceUsageAnalyzeResponse.setUsedSize(space.getTotalSize());
            spaceUsageAnalyzeResponse.setMaxSize(space.getMaxSize());
            spaceUsageAnalyzeResponse.setUsedCount(space.getTotalCount());
            spaceUsageAnalyzeResponse.setMaxCount(space.getMaxCount());

            // 计算比例
            double sizeUsageRatio = NumberUtil.round(space.getTotalSize() * 1.0 * 100 / space.getMaxSize(),2).doubleValue();
            double countUsageRatio = NumberUtil.round(space.getTotalCount() * 1.0 * 100 / space.getTotalCount(),2).doubleValue();
            spaceUsageAnalyzeResponse.setSizeUsageRatio(sizeUsageRatio);
            spaceUsageAnalyzeResponse.setCountUsageRatio(countUsageRatio);
            return spaceUsageAnalyzeResponse;


        }

    }

    @Override
    public List<SpaceCategoryAnalyzeResponse> getSpaceCategoryAnalyzeResponse(SpaceCategoryAnalyzeRequest spaceCategoryAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceCategoryAnalyzeRequest == null,ErrorCode.PARAMS_ERROR );

        // 检查权限
        checkSpaceAnalyzeAuth(spaceCategoryAnalyzeRequest, loginUser);

        // 构造查询条件 select picSize from picture where id= xxx( 这里是 SpaceId) group by category
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(spaceCategoryAnalyzeRequest,queryWrapper);

        // Mybatis-plus分组查询
        queryWrapper.select("category","count(*) as count","sum(picSize) as totalSize")
                .groupBy("category");

        List<SpaceCategoryAnalyzeResponse> responseList = pictureServiceImpl.getBaseMapper().selectMaps(queryWrapper)
                .stream()
                .map(result -> {
                    String category = (String) result.get("category");
                    Long count = (Long) result.get("count");
                    Long totalSize = ((BigDecimal) result.get("totalSize")).longValue();
                    return new SpaceCategoryAnalyzeResponse(category, count, totalSize);
                }).collect(Collectors.toList());

        return responseList;
    }

    @Override
    public List<SpaceTagAnalyzeResponse> getSpaceTagAnalyzeResponse(SpaceTagAnalyzeRequest spaceTagAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceTagAnalyzeRequest == null,ErrorCode.PARAMS_ERROR );

        checkSpaceAnalyzeAuth(spaceTagAnalyzeRequest, loginUser);

        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(spaceTagAnalyzeRequest,queryWrapper);

        // 先查出tag,再根据tag去查图片
        queryWrapper.select("tags");

        // 图片的标签字符串列表
        List<Object> tagJsonList = pictureServiceImpl.getBaseMapper().selectObjs(queryWrapper);

        List<String> tagStringList = tagJsonList.stream()
                .filter(ObjectUtil::isNotNull)
                .map(Object::toString)
                .collect(Collectors.toList());

        // 解析标签并统计 -> 扁平化 ->stream 流自动groupBy
        Map<String, Long> tagCountMap = tagStringList.stream()
                .flatMap(tagJson -> JSONUtil.toList(tagJson, String.class).stream())
                .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));

        // 转化为响应对象，并排序
        return tagCountMap.entrySet()
                .stream()
                .sorted(Comparator.comparingLong(Map.Entry::getValue))
                .map(entry -> new SpaceTagAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());

    }

    @Override
    public List<SpaceSizeAnalyzeResponse> getSpaceSizeAnalyzeResponse(SpaceSizeAnalyzeRequest spaceSizeAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceSizeAnalyzeRequest == null,ErrorCode.PARAMS_ERROR );

        checkSpaceAnalyzeAuth(spaceSizeAnalyzeRequest, loginUser);

        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(spaceSizeAnalyzeRequest,queryWrapper);

        queryWrapper.select("picSize");

        // 图片的标签字符串列表
        List<Object> sizeList = pictureServiceImpl.getBaseMapper().selectObjs(queryWrapper);
        List<Long> picSizeList = sizeList.stream()
                .filter(ObjectUtil::isNotNull)
                .map(size -> (Long) size)
                .collect(Collectors.toList());

        // 定义分段范围，使用有序Map
        Map<String,Long> sizeRanges = new LinkedHashMap<>();
        Long one_KB = 1024L;
        sizeRanges.put("<100KB",picSizeList.stream().filter(size ->size < 100 * one_KB).count());
        sizeRanges.put("100KB-500KB",picSizeList.stream().filter(size ->size > 100 * one_KB && size < 500 * one_KB).count());
        sizeRanges.put("500KB-1MB",picSizeList.stream().filter(size ->  size > 500 * one_KB  && size < 1024 * one_KB).count());
        sizeRanges.put(">1MB",picSizeList.stream().filter(size ->size > 1024 * one_KB).count());

        return sizeRanges.entrySet().stream().map(entry -> new SpaceSizeAnalyzeResponse(entry.getKey(),entry.getValue())).collect(Collectors.toList());
    }

    /**
     *  返回用户使用情况查询结果
     * @param spaceUserAnalyzeRequest
     * @param loginUser
     * @return
     */
    @Override
    public List<SpaceUserAnalyzeResponse> getSpaceUserAnalyzeResponse(SpaceUserAnalyzeRequest spaceUserAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceUserAnalyzeRequest == null,ErrorCode.PARAMS_ERROR );

        checkSpaceAnalyzeAuth(spaceUserAnalyzeRequest, loginUser);

        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(spaceUserAnalyzeRequest,queryWrapper);

        // 补充用户id 查询
        Long id = loginUser.getId();
        queryWrapper.eq(ObjectUtil.isNotNull(id),"userId",id);

        // 补充分析维度
        String timeDimension = spaceUserAnalyzeRequest.getTimeDimension();
        switch(timeDimension){
            case "day":
                queryWrapper.select("DATE_FORMAT(createTime,'%Y-%m-%d') as period","count(*) as count");
                break;
            case "week":
                queryWrapper.select("YEARWEEK(createTime) as period","count(*) as count");
                break;
            case "month":
                queryWrapper.select("DATE_FORMAT(createTime,'%Y-%m') as period","count(*) as count");
                break;
            default:
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"不支持的时间维度");
        }

        // 分组排序
        queryWrapper.groupBy("period").orderByAsc("period");

        // 封装查询返回结果
        List<Map<String,Object>> responseList = pictureServiceImpl.getBaseMapper().selectMaps(queryWrapper);

                return responseList.stream()
                .map(result -> {
                    String period = (String) result.get("period");
                    Long count = (Long) result.get("count");

                    return new SpaceUserAnalyzeResponse(period, count);
                }).collect(Collectors.toList());

    }

    @Override
    public List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeRequest spaceRankAnalyzeRequest, User loginUser) {

        // 检查权限，仅管理员查看
        ThrowUtils.throwIf(!userServiceImpl.isAdmin(loginUser),ErrorCode.NO_AUTH_ERROR);

        //构造查询条件
        QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id","spaceName","userId","totalSize")
                .orderByDesc("totalSize")
                .last("limit "+spaceRankAnalyzeRequest.getTopN());

        return spaceServiceImpl.list(queryWrapper);
    }

    /**
     *  校验空间分析的权限
     * @param spaceAnalyzeRequest
     * @param loginUser
     */
   private void checkSpaceAnalyzeAuth(SpaceAnalyzeRequest spaceAnalyzeRequest,User loginUser){
       Long spaceId = spaceAnalyzeRequest.getSpaceId();
       boolean queryPublic = spaceAnalyzeRequest.isQueryPublic();
       boolean queryAll = spaceAnalyzeRequest.isQueryAll();

       // 全空间分析或者公共图片分析，仅管理员可用
       if(queryPublic || queryAll){
           ThrowUtils.throwIf(!userServiceImpl.isAdmin(loginUser),ErrorCode.NO_AUTH_ERROR,"无权限操作");
       }else{
           // 分析特定空间，仅本人可用
           ThrowUtils.throwIf(spaceId == null,ErrorCode.PARAMS_ERROR);
           Space space = spaceServiceImpl.getById(spaceId);
           ThrowUtils.throwIf(space == null,ErrorCode.NO_AUTH_ERROR,"空间不存在");

           // 校验空间
           spaceServiceImpl.checkSpaceAuth(space,loginUser);
       }
   }

    /**
     *  根据请求对象封装查询条件
     * @param spaceAnalyzeRequest
     * @param queryWrapper
     */
    private void fillAnalyzeQueryWrapper(SpaceAnalyzeRequest spaceAnalyzeRequest,QueryWrapper<Picture> queryWrapper){
        Long spaceId = spaceAnalyzeRequest.getSpaceId();
        boolean queryPublic = spaceAnalyzeRequest.isQueryPublic();
        boolean queryAll = spaceAnalyzeRequest.isQueryAll();

        // 全空间分析
        if(queryAll){
            return;
        }

        // 公共空间分析
        if(queryPublic){
            queryWrapper.isNull("spaceId");
            return;
        }

        //特定空间分析
        if(spaceId != null){
            queryWrapper.eq("spaceId", spaceId);
            return;
        }

        throw new BusinessException(ErrorCode.PARAMS_ERROR,"未指定查询范围 ");
    }


}




